package com.yingxue.lesson.service.impl;

import com.yingxue.lesson.contants.Constant;
import com.yingxue.lesson.entity.SysPermission;
import com.yingxue.lesson.exception.BusinessException;
import com.yingxue.lesson.exception.code.BaseResponseCode;
import com.yingxue.lesson.mapper.SysPermissionMapper;
import com.yingxue.lesson.service.PermissionService;
import com.yingxue.lesson.service.RedisService;
import com.yingxue.lesson.service.RolePermissionService;
import com.yingxue.lesson.service.UserRoleService;
import com.yingxue.lesson.utils.TokenSetting;
import com.yingxue.lesson.vo.req.PermissionAddReqVO;
import com.yingxue.lesson.vo.req.permissionVo.PermissionUpdateReqVO;
import com.yingxue.lesson.vo.resp.PermissionRespNodeVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class PermissionServiceImpl implements PermissionService {

    @Autowired
    private SysPermissionMapper permissionMapper;
    @Autowired
    private RolePermissionService rolePermissionService;
    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private TokenSetting tokenSetting;

    /**
     * 查询所有菜单
     */
    @Override
    public List<SysPermission> selectAll() {
        List<SysPermission> sysPermissions = permissionMapper.selectAll();
        if(!sysPermissions.isEmpty()){
            for (SysPermission sysPermission : sysPermissions) {
                SysPermission parent = permissionMapper.selectByPrimaryKey(sysPermission.getPid());
                if(parent!=null){
                    sysPermission.setPidName(parent.getName());
                }
            }
        }
        return sysPermissions;

    }


    /**
     * 查询所有菜单--树形结构展示
     */
    @Override
    public List<PermissionRespNodeVO> selectAllMenuByTree() {
        List<SysPermission> list=permissionMapper.selectAll();
        List<PermissionRespNodeVO> result=new ArrayList<>();
        PermissionRespNodeVO respNodeVO=new PermissionRespNodeVO();
        respNodeVO.setId("0");
        respNodeVO.setTitle("默认顶级菜单");
        respNodeVO.setChildren(getTree(list,true));
        result.add(respNodeVO);
        return result;
    }

    /**
     * 递归遍历所有数据
     * 修改菜单权限树递归方法，新增一个参数type：true(只查询目录和菜单) false(查询目录、菜单、按钮权限)
     */
    private List<PermissionRespNodeVO> getTree(List<SysPermission> all,boolean type){
        List<PermissionRespNodeVO> list=new ArrayList<>();
        if (all==null||all.isEmpty()){
            return list;
        }
        for(SysPermission sysPermission:all){
            if(sysPermission.getPid().equals("0")){
                PermissionRespNodeVO permissionRespNode=new PermissionRespNodeVO();
                BeanUtils.copyProperties(sysPermission,permissionRespNode);
                permissionRespNode.setTitle(sysPermission.getName());
                if(type){
                    permissionRespNode.setChildren(getChildExcBtn(sysPermission.getId(),all));
                }else {
                    permissionRespNode.setChildren(getChild(sysPermission.getId(),all));
                }
                list.add(permissionRespNode);
            }
        }
        return list;
    }

    /**
     * 只递归到菜单
     */
    private List<PermissionRespNodeVO> getChildExcBtn(String id,List<SysPermission> all){
        List<PermissionRespNodeVO> list=new ArrayList<>();
        for(SysPermission sysPermission:all){
            if(sysPermission.getPid().equals(id)&&sysPermission.getType()!=3){
                PermissionRespNodeVO permissionRespNode=new PermissionRespNodeVO();
                BeanUtils.copyProperties(sysPermission,permissionRespNode);
                permissionRespNode.setTitle(sysPermission.getName());
                permissionRespNode.setChildren(getChildExcBtn(sysPermission.getId(),all));
                list.add(permissionRespNode);
            }
        }
        return list;
    }

    /**
     * 递归遍历所有数据 到按钮
     */
    private List<PermissionRespNodeVO> getChild(String id,List<SysPermission> all){

        List<PermissionRespNodeVO> list=new ArrayList<>();
        for (SysPermission s:
                all) {
            if(s.getPid().equals(id)){
                PermissionRespNodeVO respNodeVO=new PermissionRespNodeVO();
                BeanUtils.copyProperties(s,respNodeVO);
                respNodeVO.setTitle(s.getName());
                respNodeVO.setChildren(getChild(s.getId(),all));
                list.add(respNodeVO);
            }
        }
        return list;
    }

    /**
     * *********************************************************************************************************
     */

    /**
     * 添加菜单
     */
    @Override
    public SysPermission addPermission(PermissionAddReqVO vo) {
        SysPermission sysPermission=new SysPermission();
        BeanUtils.copyProperties(vo,sysPermission);
        verifyForm(sysPermission);
        sysPermission.setId(UUID.randomUUID().toString());
        sysPermission.setCreateTime(new Date());
        int insert = permissionMapper.insertSelective(sysPermission);
        if(insert!=1){
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        return sysPermission;
    }


    /**
     * - 操作后的菜单类型是目录的时候 父级必须为目录
     * - 操作后的菜单类型是菜单的时候，父类必须为目录类型
     * - 操作后的菜单类型是按钮的时候 父类必须为菜单类型
     */
    private void verifyForm(SysPermission sysPermission){
        SysPermission parent=permissionMapper.selectByPrimaryKey(sysPermission.getPid());
        switch (sysPermission.getType()){
            case 1:
                if(parent!=null){
                    if(parent.getType()!=1){
                        throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_CATALOG_ERROR);
                    }
                }else if (!sysPermission.getPid().equals("0")){
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_CATALOG_ERROR);
                }
                break;
            case 2:
                if(parent==null||parent.getType()!=1){
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_MENU_ERROR);
                }
                if(StringUtils.isEmpty(sysPermission.getUrl())){
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_NOT_NULL);
                }
                break;
            case 3:
                if(parent==null||parent.getType()!=2){
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_BTN_ERROR);
                }
                if(StringUtils.isEmpty(sysPermission.getPerms())){
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_PERMS_NULL);
                }
                if(StringUtils.isEmpty(sysPermission.getUrl())){
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_NOT_NULL);
                }
                if(StringUtils.isEmpty(sysPermission.getMethod())){
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_METHOD_NULL);
                }
                if(StringUtils.isEmpty(sysPermission.getCode())){
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_CODE_NULL);
                }
                break;
        }
    }

    /**
     * 查询左侧菜单
     * @param userId
     */
    @Override
    public List<PermissionRespNodeVO> permissionTreeList(String userId) {
        return getTree(selectAll(),true);
    }

    /**
     *查询所有菜单权限 树列表 到按钮
     */
    @Override
    public List<PermissionRespNodeVO> selectAllTree() {
        return getTree(selectAll(),false);
    }

    /**
     * 更新菜单权限
     */
    @Override
    public void updatePermission(PermissionUpdateReqVO vo) {
        //1.校验数据
        SysPermission update = new SysPermission();
        BeanUtils.copyProperties(vo,update);
        verifyForm(update);
        SysPermission permission = permissionMapper.selectByPrimaryKey(vo.getId());
        if (permission == null){
            log.info("传入的id在数据库中不存在");
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        //2.所属菜单发生了变化或者权限状态发生了变化要校验该权限是否存在子集
        if (!permission.getPid().equals(vo.getPid()) || permission.getStatus() != vo.getStatus()){
            List<SysPermission> childPermission = permissionMapper.selectChild(vo.getId());
            if (!childPermission.isEmpty()){
                throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_UPDATE);
            }
        }
        //3.更新
        update.setUpdateTime(new Date());
        int i = permissionMapper.updateByPrimaryKeySelective(update);
        if (i!=1){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }
        //4.判断授权标识符是否发生了变化(权限标识符发生了变化，或者权限状态发生了变化)
        if ( !permission.getPerms().equals(vo.getPerms()) || permission.getStatus() != vo.getStatus()){
            List<String> roleIdsByPermissionId = rolePermissionService.getRoleIdsByPermissionId(vo.getId());
            if (!roleIdsByPermissionId.isEmpty()){
                List<String> userIdsByRoleIds = userRoleService.getUserIdsByRoleIds(roleIdsByPermissionId);
                if (!userIdsByRoleIds.isEmpty()){
                    for (String userId : userIdsByRoleIds) {
                        redisService.set(Constant.ACCOUNT_LOCK_KEY+userId,userId,tokenSetting.getAccessTokenExpireTime().toMillis(), TimeUnit.MILLISECONDS);
                        /**
                         * 清楚用户授权数据缓存
                         */
                        redisService.delete(Constant.IDENTIFY_CACHE_KEY+userId);
                    }
                }
            }
        }

    }


    /**
     * 删除菜单权限
     */
    @Override
    public void deleted(String permissionId) {
        //1.判断是否存在子集
        List<SysPermission> childPermission = permissionMapper.selectChild(permissionId);
        if (!childPermission.isEmpty()){
            throw new BusinessException(BaseResponseCode.ROLE_PERMISSION_RELATION);
        }
        //2.逻辑删除菜单权限数据
        SysPermission sysPermission = new SysPermission();
        sysPermission.setUpdateTime(new Date());
        sysPermission.setDeleted(0);
        sysPermission.setId(permissionId);
        int i = permissionMapper.updateByPrimaryKeySelective(sysPermission);
        if (i!=1){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }
        //3.物理删除角色和该菜单权限的关联
        rolePermissionService.removeByPermission(permissionId);
        //4.判断权限标识符是否发生变化
        List<String> roleIds = rolePermissionService.getRoleIdsByPermissionId(permissionId);
        //5.要标注和该菜单权限关联用户(需要主动刷新token 重新签发)
        if (!roleIds.isEmpty()){
            List<String> userIds = userRoleService.getUserIdsByRoleIds(roleIds);
            for (String userId : userIds) {
                redisService.set(Constant.JWT_REFRESH_KEY+userId,userId,tokenSetting.getAccessTokenExpireTime().toMillis(),TimeUnit.MILLISECONDS);
                //清楚用户授权数据缓存
                redisService.delete(Constant.IDENTIFY_CACHE_KEY+userId);
            }
        }
    }

    /**
     * 通过 userId 查询 菜单权限
     */
    @Override
    public List<String> getPermissionByUserId(String userId) {

        //1.调用封装方法（得到菜单权限）
        List<SysPermission> permission = getPermission(userId);
        if (permission == null || permission.isEmpty()){
            return null;
        }
        //2.设置 授权
        ArrayList<String> list = new ArrayList<>();
        for (SysPermission s : permission) {
            if (!StringUtils.isEmpty(s.getPerms())){
                list.add(s.getPerms());
            }
        }
        return list;
    }


    /**
     * 得到菜单权限
     */
    public List<SysPermission> getPermission(String userId){
        //1.通过userId 查询 roleIds
        List<String> roleIds = userRoleService.getRoleIdsByUserId(userId);
        if (roleIds.isEmpty()){
            return null;
        }
        //2.通过 roleIds 查询 permissionIds
        List<String> permissionIds = rolePermissionService.getPermissionIdsByRoleIds(roleIds);
        if (permissionIds.isEmpty()){
            return null;
        }
        //3.通过 permissionIds 查询 菜单权限集合
        List<SysPermission> permission = permissionMapper.getPermissionByPermissionIds(permissionIds);

        return permission;
    }
}